/*
 * Copyright 2021-2022 by Nedim Sabic Sabic
 * https://www.fibratus.io
 * All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package main

import (
	"bytes"
	"fmt"
	"github.com/Masterminds/sprig/v3"
	"github.com/rabbitstack/fibratus/pkg/event"
	"io"
	"log"
	"math"
	"os"
	"text/template"
)

// Source contains the required data for producing the input for the message compiler.
type Source struct {
	Categories []string
	Events     []event.Info
	MaxEvents  uint16
}

func (s *Source) Generate(w io.Writer) error {
	funcmap := sprig.TxtFuncMap()
	funcmap["length"] = func(evts []event.Info) int {
		return len(evts)
	}
	funcmap["N"] = func(start, end int) (stream chan int) {
		stream = make(chan int)
		go func() {
			for i := start; i <= end; i++ {
				stream <- i
			}
			close(stream)
		}()
		return
	}
	t := template.Must(template.New("main").Funcs(funcmap).Parse(srcTemplate))
	err := t.Execute(w, s)
	if err != nil {
		return fmt.Errorf("failed to execute template: %v", err)
	}
	return nil
}

func main() {
	var buf bytes.Buffer

	src := &Source{
		Categories: event.Categories(),
		Events:     event.GetTypesMetaIndexed(),
		MaxEvents:  math.MaxUint16,
	}

	if err := src.Generate(&buf); err != nil {
		log.Fatal(err)
	}
	if err := os.WriteFile("mc/fibratus.mc", buf.Bytes(), 0644); err != nil {
		log.Fatal(err)
	}
}

const srcTemplate = `
;// Code generated by 'go generate'; DO NOT EDIT.
MessageIdTypedef=DWORD

LanguageNames=(English=0x409:MSG00409)

;//************** Event categories ************
{{- range $i, $cat := .Categories }}
MessageId={{ add1 $i }}
SymbolicName={{title $cat}}
Language=English
{{ title $cat }}
.
{{- end }}

{{ $catOffset := 25 }}

;//*********** Event types **************
{{- range $i, $e := .Events }}
MessageId={{ add $i $catOffset }}
SymbolicName={{ $e.Name }}
Language=English
{{ $e.Description }}
.
{{- end }}

{{ $n := length .Events }}
{{ $n = add $n $catOffset | int }}
{{ $e := sub .MaxEvents $n | int }}

{{- range $i, $_ := N $n $e }}
MessageId={{ add $i $n }}
SymbolicName=Reserved{{ add $i $n }}
Language=English
%1
.
{{- end }}
`
